
#[cfg(not(feature = "openssl"))]
pub mod sha {
	pub use sha1::Sha1;
	pub use sha2::Sha224;
	pub use sha2::Sha256;
	pub use sha2::Sha384;
	pub use sha2::Sha512;
}

#[cfg(not(feature = "openssl"))]
use sha1::Digest;

#[cfg(feature = "openssl")]
use openssl::sha;

pub const SHA1:usize = 20; 
pub const SHA224:usize = 28; 
pub const SHA256:usize = 32; 
pub const SHA384:usize = 48; 
pub const SHA512:usize = 64;

pub trait FingerPrintComputer {
	fn fp(data:&[u8]) -> Self;
}

pub trait FingerPrintHasher {
	fn fp(data:&[u8]) -> Self;
	fn as_ref(&self) -> &[u8];
	fn as_mut(&mut self) -> &mut[u8];
}

#[cfg(feature = "openssl")]
macro_rules! sha_fingerprint_computer {
	($(($name:ident,$len:expr)),*) => {
		$(
			impl FingerPrintComputer for [u8;$len] {
				fn fp(data:&[u8]) -> Self {
					sha::$name(data)
				}
			}
		)*	
	}
}

#[cfg(not(feature = "openssl"))]
macro_rules! sha_fingerprint_hasher {
	($(($name:ident,$len:expr)),*) => {
		$(
			impl FingerPrintHasher for [u8;$len] {
				fn fp(data:&[u8]) -> Self {
					let mut hasher = sha::$name::new();
					hasher.update(data);
					hasher.finalize().into()
				}
				
				fn as_ref(&self) -> &[u8] {
					self
				}
				
				fn as_mut(&mut self) -> &mut[u8] {
					self
				}
			}
			
		)*	
	}
}

#[cfg(feature = "openssl")]
macro_rules! sha_fingerprint_hasher {
	($(($name:ident,$len:expr)),*) => {
		$(
			impl FingerPrintHasher for [u8;$len] {
				fn fp(data:&[u8]) -> Self {
					let mut hasher = sha::$name::new();
					hasher.update(data);
					hasher.finish()
				}
				
				fn as_ref(&self) -> &[u8] {
					self
				}
				
				fn as_mut(&mut self) -> &mut[u8] {
					self
				}
			}
			
		)*	
	}
}

#[cfg(feature = "openssl")]
sha_fingerprint_computer! {
	(sha1,SHA1),
	(sha224,SHA224),
	(sha256,SHA256),
	(sha384,SHA384),
	(sha512,SHA512)
}

sha_fingerprint_hasher! {
	(Sha1,SHA1),
	(Sha224,SHA224),
	(Sha256,SHA256),
	(Sha384,SHA384),
	(Sha512,SHA512)
}
